package com.lee.web.asyncthreadpool.async;

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.*;


/**
 * @author edz
 * @EnableAsync 注解表示启用异步，getAsyncExecutor方法表示提供给Spring一个异步线程池，
 * spring会将以@Async注解标记的方法放入线程池中异步执行
 */
@EnableAsync
@Configuration
public class AsyncThreadPool implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {

        /**
         * spring 提供的线程池 ThreadPoolTaskExecutor
         */
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(5);
        taskExecutor.setMaxPoolSize(10);
        taskExecutor.setKeepAliveSeconds(1000);
        taskExecutor.setQueueCapacity(5);
//        taskExecutor.setAllowCoreThreadTimeOut(false);
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        taskExecutor.initialize();


        /**
         *  jdk 提供的线程池，ThreadPoolExecutor
         */
        // corePoolSize：核心线程数，线程池初始化后没有线程，当有任务来时才会创建线程，当线程数达到核心线程数的话，会将新建的线程放入阻塞队列中
        // maximumPoolSize：最大线程数，表明线程池能创建的最大线程数
        // keepAliveTime：空闲线程保存时间，当线程中任务执行完毕后，线程空闲，这个时间是指定空闲线程的销毁时间
        // timeUnit：空闲线程保存时间的单位
        // BlockingQueue<Runnable>：阻塞队列
        // ThreadFactory：线程工厂
        // RejectedExecutionHandler：队列已满，而且任务量大于最大线程的异常处理策略
        // ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
        // ThreadPoolExecutor.DiscardPolicy：也是丢弃任务，但是不抛出异常。
        // ThreadPoolExecutor.DiscardOldestPolicy：丢弃队列最前面的任务，然后重新尝试执行任务（重复此过程）
        // ThreadPoolExecutor.CallerRunsPolicy：由调用线程处理该任务
        ArrayBlockingQueue<Runnable> tasks = new ArrayBlockingQueue<>(20);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 30000, TimeUnit.SECONDS, tasks);

        return taskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

        return null;
    }

    public static void main(String[] args) {
        ArrayBlockingQueue<Runnable> tasks = new ArrayBlockingQueue<Runnable>(2);
        ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(2, 5, 3000, TimeUnit.MILLISECONDS, tasks, new ThreadPoolExecutor.AbortPolicy());
        for (int i = 0; i < 10; i++) {
            threadPoolExecutor.submit(() -> {
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(8000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            System.out.println(threadPoolExecutor.getQueue().size());
        }
        System.out.println("ending");
    }
}
